package cn.com.nes.site.service.system.company.impl;

import cn.com.nes.common.exception.IllegalBusinessException;
import cn.com.nes.common.exception.MissBusinessParameterException;
import cn.com.nes.common.util.tree.TreeBuilder;
import cn.com.nes.common.web.CommonResult;
import cn.com.nes.mybatis.agent.system.entity.Company;
import cn.com.nes.mybatis.agent.system.entity.Department;
import cn.com.nes.mybatis.agent.system.entity.TAgentFacturer;
import cn.com.nes.mybatis.agent.system.entity.TUser;
import cn.com.nes.mybatis.agent.system.mapper.CompanyMapper;
import cn.com.nes.mybatis.agent.system.mapper.TAgentFacturerMapper;
import cn.com.nes.site.entity.PageData;
import cn.com.nes.site.entity.em.CompanyTypeEnum;
import cn.com.nes.site.entity.em.DeleteEnum;
import cn.com.nes.site.entity.em.product.ProductAttributeEnum;
import cn.com.nes.site.entity.vo.NullVO;
import cn.com.nes.site.entity.vo.system.CompanyTreeNodeVO;
import cn.com.nes.site.entity.vo.user.DeleteBusinessCompanyVo;
import cn.com.nes.site.entity.vo.user.SaveBusinessCompanyVo;
import cn.com.nes.site.entity.vo.workOrder.QueryCompanyVO;
import cn.com.nes.site.rocketmq.producer.MessageService;
import cn.com.nes.site.service.agent.AgentFacturerService;
import cn.com.nes.site.service.product.AsyncSaveProductSeriesService;
import cn.com.nes.site.service.product.bo.SaveProductSeriesAndEnergyBO;
import cn.com.nes.site.service.system.company.BusinessCompanyService;
import cn.com.nes.site.service.system.company.DepartmentService;
import cn.com.nes.site.service.system.company.ManufactureService;
import cn.com.nes.site.service.system.company.bo.QueryAgentCompanyBO;
import cn.com.nes.site.service.system.company.dto.CompanyTreeNodeDTO;
import cn.com.nes.site.service.system.user.SystemUserService;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@EnableAsync
public class BusinessCompanyServiceImpl extends ServiceImpl<CompanyMapper, Company> implements BusinessCompanyService {

    @Resource
    private TAgentFacturerMapper tAgentFacturerMapper;

    @Resource
    private ManufactureService manufactureService;

    @Resource
    private DepartmentService departmentService;

    @Resource
    @Lazy
    private SystemUserService systemUserService;

    @Resource(name = "transactionManager_ope")
    private DataSourceTransactionManager transactionManagerOpe;

    @Resource
    private AsyncSaveProductSeriesService asyncSaveProductSeriesService;

    @Resource
    private AgentFacturerService agentFacturerService;

//    @Autowired
//    private MessageService messageService;


    @Transactional(rollbackFor = Exception.class)
    @Override
    public PageData saveBusinessCompany(SaveBusinessCompanyVo vo) throws Exception {
        Company company = new Company();
        DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
        transactionDefinition.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRES_NEW);
        TransactionStatus transactionStatus = transactionManagerOpe.getTransaction(transactionDefinition);
        try {

            boolean addCompany = false;
            if (StrUtil.isEmpty(vo.getCompanyId())) {
                addCompany = true;
                // 公司类别为子公司，添加父公司信息
                if ("03".equals(vo.getCompanyType())) {
                    company.setPCompanyId(vo.getPid());
                    company.setPCompanyname(vo.getPname());
                } else {
                    company.setPCompanyId("0000");
                    company.setPCompanyname("北京创今世纪科技有限公司");
                }
                company.setCompanytype(vo.getCompanyType());
                company.setCompanyid(generateCompanyId(company.getPCompanyId()));
                company.setNesCompanyid(company.getCompanyid());
                company.setSfsc(0);
                company.setGmtCreate(vo.getOperateDate());
                company.setGmtCreateId(vo.getOperateUserId());
            } else {
                company = this.baseMapper.getCompanyUnDelete(vo.getCompanyId());
                company.setGmtModified(vo.getOperateDate());
                company.setGmtModifiedId(vo.getOperateUserId());
            }

            company.setCompanyname(vo.getCompanyFullName());
            company.setShortname(vo.getCompanyShortName());
            company.setLegalperson(vo.getLegalPerson());
            company.setUniformsocialcreditcode(vo.getUniformSocialCreditCode());
            company.setOrganizationCode(vo.getOrganizationCode());
            company.setContact(vo.getContact());
            company.setContactnumber(vo.getContactNumber());
            company.setAreacode(vo.getAreaCode());
            company.setAddress(vo.getRegisterAddress());
            company.setChannel(vo.getChannel());

            if (addCompany) {
                this.baseMapper.insert(company);
                // 新增公司类型为03（子公司时），子公司是一种一对一的代理关系，需要创建代理关系
                if ("03".equals(company.getCompanytype())) {
                    TAgentFacturer tAgentFacturer = new TAgentFacturer();
                    tAgentFacturer.setAgentId(company.getCompanyid());
                    tAgentFacturer.setFacturerId(vo.getPid());
                    tAgentFacturer.setDeleted(0);
                    tAgentFacturer.setGmtCreate(new Date());
                    tAgentFacturer.setGmtCreateId(vo.getOperateUserId());
                    tAgentFacturerMapper.insert(tAgentFacturer);
                }
                // 自动创建品牌系列
                saveProductSeries(vo, company);
            } else {
                this.baseMapper.updateById(company);
            }

            String username = vo.getUserInfo() != null ? vo.getUserInfo().getUsername() : "";
            manufactureService.saveOpeCompany(company, username, addCompany);
            transactionManagerOpe.commit(transactionStatus);
        } catch (Exception e) {
            transactionManagerOpe.rollback(transactionStatus);
            log.error("保存公司 -> 同步创建厂商平台公司: {}", e);
            throw new RuntimeException(e.getMessage());
        }

        PageData pageData = PageData.ok();
        pageData.setKey(company.getCompanyid());
       return pageData;

    }

    // 自动创建品牌系列
    private void saveProductSeries(SaveBusinessCompanyVo vo, Company company) {
        try {
            if (ObjectUtil.isNull(vo) || ObjectUtil.isNull(company)) {
                throw new MissBusinessParameterException("vo & company");
            }
            SaveProductSeriesAndEnergyBO saveProductSeriesBO = vo.convertToBo(SaveProductSeriesAndEnergyBO.class);
            saveProductSeriesBO.setParentId(null);
            saveProductSeriesBO.setNodeType(ProductAttributeEnum.BRAND.getKey());
            saveProductSeriesBO.setNodeName(company.getCompanyname());
            saveProductSeriesBO.setRemark(company.getCompanyname() + "默认品牌系列");
            saveProductSeriesBO.setSort(0);
            saveProductSeriesBO.setEnable(true);
            saveProductSeriesBO.setCompanyId(company.getCompanyid());
            saveProductSeriesBO.setAreaCode(company.getAreacode());
            asyncSaveProductSeriesService.saveProductSeries(saveProductSeriesBO);
        } catch (Exception e) {
            log.error("创建新的公司同步创建品牌失败!");
        }
    }


    /**
     * 生成公司ID
     * @param parentCompanyId 父公司ID
     * @return
     */
    private String generateCompanyId(String parentCompanyId) {
        String lastChildComapnyId = this.baseMapper.getLastChildComapnyId(parentCompanyId);
        String newCompanyId = "";
        int nextCompanyId = Integer.parseInt(lastChildComapnyId) + 1;
        if (nextCompanyId > 999) {
            newCompanyId = String.valueOf(nextCompanyId);
        } else if (nextCompanyId > 99 && nextCompanyId <= 999) {
            newCompanyId = String.valueOf("0" + nextCompanyId);
        } else if (nextCompanyId > 9 && nextCompanyId <= 99) {
            newCompanyId = String.valueOf("00" + nextCompanyId);
        } else if (nextCompanyId <= 9) {
            newCompanyId = String.valueOf("000" + nextCompanyId);
        }
        if (newCompanyId != null && !"".equals(newCompanyId)) {
            newCompanyId = parentCompanyId + newCompanyId;
        }
        log.debug("创建公司 -> 数据库中查询到的公司ID[{}]，生成公司ID[{}]", lastChildComapnyId, newCompanyId);
        return newCompanyId;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public PageData deleteBusinessCompany(DeleteBusinessCompanyVo vo) throws Exception {
        Company needsDeletedCompany = this.baseMapper.getCompanyUnDelete(vo.getCompanyId());

        //  删除之前，判断是否存在子公司及子部门
        boolean hasChildCompanyOrDepartment = hasChildCompanyOrDepartment(vo.getCompanyId());
        if (hasChildCompanyOrDepartment) {
            return PageData.error("存在子公司及部门，不能删除");
        }

        //  删除之前，判断是否存在代理关系
        boolean hasAgencyRelationship = hasAgencyRelationship(vo.getCompanyId());
        if (hasAgencyRelationship && !"03".equals(needsDeletedCompany.getCompanytype())) {
            return PageData.error("存在代理关系，不能删除");
        }

        // 删除之前，判断是否存在员工
        boolean hasUsers = companyHasUsers(vo.getCompanyId());
        if (hasUsers) {
            return PageData.error("公司下有员工，不能删除");
        }

        needsDeletedCompany.setSfsc(1);
        needsDeletedCompany.setGmtModifiedId(vo.getOperateUserId());
        needsDeletedCompany.setGmtModifiedId(vo.getOperateUserId());
        this.baseMapper.updateById(needsDeletedCompany);

        // 公司类型不是00（创今公司）的，需要删除厂商-代理商对应关系
        if (!"00".equals(needsDeletedCompany.getCompanytype())) {
            tAgentFacturerMapper.deleteRelation(vo.getCompanyId());
        }

        return PageData.ok();
    }

    /**
     * 判断是否存在员工
     * @param companyId
     * @return
     */
    private boolean companyHasUsers(String companyId) throws Exception {
        List<TUser> hasUsers = systemUserService.getUsers(companyId);
        if (CollUtil.isNotEmpty(hasUsers)) {
            return true;
        }
        return false;
    }

    /**
     * 判断是否存在代理关系
     * @param companyId
     * @return
     */
    private boolean hasAgencyRelationship(String companyId) {
        List<TAgentFacturer> hasAgentFacturers = tAgentFacturerMapper.hasAgencyRelationship(companyId);
        if (CollUtil.isNotEmpty(hasAgentFacturers)) {
            return true;
        }
        return false;
    }

    /**
     * 判断是否存在子公司或者子部门
     * @param companyId 公司ID
     * @return
     */
    private boolean hasChildCompanyOrDepartment(String companyId) throws Exception {
        // 判断存在子公司
        List<Company> childCompanys = this.baseMapper.getChildCompanys(companyId);
        if (CollUtil.isNotEmpty(childCompanys)) {
            return true;
        }

        // 判断存在子部门
        List<Department> childDepartments = departmentService.hasNextLevel(companyId);
        if (CollUtil.isNotEmpty(childDepartments)) {
            return true;
        }

        return false;
    }

    @Override
    public void bindCompanyId(String companyId, String callCenterCompanyId) {
        try {
            QueryWrapper<Company> wrapper = new QueryWrapper<>();
            wrapper.eq("companyId", companyId);
            wrapper.eq("sfsc", 0);

            Company oldCompany = this.getOne(wrapper);
            if (Objects.isNull(oldCompany)) {
                return;
            }

            oldCompany.setCcCompanyId(callCenterCompanyId);
            this.baseMapper.updateById(oldCompany);

            log.info("绑定公司id完成!");
        } catch (Exception e) {
            log.info("绑定公司id失败!");
        }
    }

    @Override
    public Company getCompany(String companyId) throws Exception {
        Company company = this.baseMapper.getCompanyUnDeleted(companyId);
        if (ObjectUtil.isNull(company)) {
            throw new IllegalBusinessException("公司不存在！");
        }
        return company;
    }

    @Override
    public List<Company> getCompanys(Set<String> companyIds) {
        QueryWrapper<Company> wrapper = new QueryWrapper<>();
        wrapper.in("companyId", companyIds);
        wrapper.eq("sfsc", 0);
        List<Company> companies = this.baseMapper.selectList(wrapper);
        return companies;
    }

    @Override
    public Page<Company> getCompanys(QueryCompanyVO vo) {
        Page<Company> companyPage = new Page<>(vo.getPageid(), vo.getPagesize());
        List<Company> companies = this.baseMapper.getCompanys(companyPage, vo.getOperateUserCompanyId(), vo.getOperateUserCompanyType(), vo.getQuery());
        companyPage.setRecords(companies);
        return companyPage;
    }

    @Override
    public Set<String> getCcCompanyIdSet(String companyType, String companyId) throws Exception {
        Set<String> ccCompanyIdSet = new HashSet<>();

        // 创今公司查询全部工单 - 返回空集合,就不会用公司id做过滤
        if (ObjectUtil.isNull(companyType) || CompanyTypeEnum._00.getKey().equals(companyType)) {
            return ccCompanyIdSet;
        }

        Company company = this.getCompany(companyId);
        ccCompanyIdSet.add(company.getCcCompanyId());

        // 厂商查询自己和全部代理商的工单
        if (CompanyTypeEnum._01.getKey().equals(companyType)) {
            ccCompanyIdSet.addAll(this.baseMapper.getCcCompanyIdSet(companyId));
            return ccCompanyIdSet;
        }

        // 代理商和子公司只查询自己的工单
        return ccCompanyIdSet;
    }

    @Override
    public CommonResult<?> queryAgentCompany(QueryAgentCompanyBO bo) throws Exception {
        if (StrUtil.isBlank(bo.getManufacturerId())) {
            throw new MissBusinessParameterException("manufacturerId must not null");
        }

        /*
         * 查询步骤：
         * 1、根据厂商id查询对应的公司信息
         * 2、根据获取到的公司信息查询它的代理商公司信息
         * 3、如果入参包含设备类型id - 以授权产品再次过滤
         * 4、获取结果集对应的客服中心id集合
         */

        // 根据厂商id查询对应的公司信息
        QueryWrapper<Company> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("sfsc", DeleteEnum._0.getKey());
        queryWrapper.eq("companyType", CompanyTypeEnum._01.getKey());
        queryWrapper.eq("nes_companyId", bo.getManufacturerId());
        List<Company> companyList = this.baseMapper.selectList(queryWrapper);
        if (CollectionUtil.isEmpty(companyList)) {
            return CommonResult.page(Collections.emptyList());
        }

        Company mainCompanyInfo = companyList.get(0);
        if (ObjectUtil.isNull(mainCompanyInfo)) {
            return CommonResult.page(Collections.emptyList());
        }

        // 根据获取到的公司信息查询它的代理商公司信息,如果入参包含设备类型id就以授权产品再次过滤
        Set<String> agentCompanyInfoIdSet = agentFacturerService.queryAgentCompanyInfoList(mainCompanyInfo.getCompanyid(), bo.getSblxId());
        List<Company> agentCompanyInfoSet = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(agentCompanyInfoIdSet)) {
            agentCompanyInfoSet.addAll(this.getCompanys(agentCompanyInfoIdSet));
        }

        // 获取结果集对应的客服中心id集合
        agentCompanyInfoSet.add(mainCompanyInfo);
        List<String> ccCompanyIdSet = agentCompanyInfoSet.stream()
                .map(Company::getCcCompanyId)
                .filter(StrUtil::isNotBlank)
                .distinct()
                .collect(Collectors.toList());

        return CommonResult.page(ccCompanyIdSet);
    }

    @Override
    public List<Company> getCompanyByUniformSocialCreditCode(String uniformSocialCreditCode) {
        QueryWrapper<Company> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("uniformSocialCreditCode", uniformSocialCreditCode);
        queryWrapper.eq("sfsc",  DeleteEnum._0.getKey());
        return this.baseMapper.selectList(queryWrapper);
    }

    @Override
    public boolean updateCompany(String companyId, String callCenterCompanyId) {
        int count = this.baseMapper.updateCompany(companyId, callCenterCompanyId);
        boolean b = false;
        if (count > 0) {
            b = true;
        }
        return b;
    }

    @Override
    public List<CompanyTreeNodeDTO> getCompanyAndDepartmentTreeNode(NullVO vo) throws Exception {
        List<CompanyTreeNodeDTO> root = getCompanyTreeNodeList(vo.getOperateUserCompanyId());
        if (CollUtil.isEmpty(root)) {
            return Collections.emptyList();
        }
        // 查询部门
        List<String> companyIds = root.stream().map(CompanyTreeNodeDTO::getId).collect(Collectors.toList());
        root.addAll(departmentService.getCompanyTreeNodeList(companyIds));
        return new TreeBuilder<CompanyTreeNodeDTO>().buildTree(root);
    }

    @Override
    public List<CompanyTreeNodeDTO> getCompanyTreeNode(CompanyTreeNodeVO vo) throws Exception {
        List<CompanyTreeNodeDTO> root = getCompanyTreeNodeList(vo.getCompanyId());
        return new TreeBuilder<CompanyTreeNodeDTO>().buildTree(root);
    }

    @Override
    public Company getCompanyByCallCenterCompanyId(Long callCenterCompanyId) {
        QueryWrapper<Company> wrapper = new QueryWrapper<>();
        wrapper.eq("cc_companyId", callCenterCompanyId);
        wrapper.eq("sfsc", 0);
        Company company = this.getOne(wrapper);

        if (ObjectUtil.isNull(company)) {
            return null;
        }
        return company;
    }

    private List<CompanyTreeNodeDTO> getCompanyTreeNodeList(String companyId) throws Exception {
        CompanyTreeNodeDTO rootCompanyTreeNodeDTO = this.baseMapper.getRootCompanyTreeNode(companyId);
        if (ObjectUtil.isEmpty(rootCompanyTreeNodeDTO)) {
            return Collections.emptyList();
        }
        List<CompanyTreeNodeDTO> root = new ArrayList<>();
        root.add(rootCompanyTreeNodeDTO);
        root.addAll(getChildren(rootCompanyTreeNodeDTO.getId()));
        return root;
    }

    private List<CompanyTreeNodeDTO> getChildren(String parentCompanyId) {
        List<CompanyTreeNodeDTO> children = this.baseMapper.getCompanyTreeNodeList(parentCompanyId);
        List<CompanyTreeNodeDTO> result = new ArrayList<>(children);
        for (CompanyTreeNodeDTO child : children) {
            result.addAll(getChildren(child.getId()));
        }
        return result;
    }

}
